﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "GroupTypeEditModeBehavior.h"
#include "DbObjectUtils.h"
#include "IElementParentReporter.h"
#include "IEditMode.h"
#include "IGroupType.h"
#include "IDocument.h"
#include "GroupElementChangeHandler.h"
#include "IElementStatus.h"
#include "IGroup.h"
#include "IElementBasicInformation.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;



DBOBJECT_DATA_DEFINE(GroupTypeEditModeBehavior)
{
    m_pElementChangeEventHandler = nullptr;
}

GroupTypeEditModeBehavior::~GroupTypeEditModeBehavior(void)
{
}

IEditMode * GroupTypeEditModeBehavior::Create(IDocument * pDoc)
{
    return IEditMode::Create(pDoc, NEW_AS_OWNER_PTR(GroupTypeEditModeBehavior));
}

bool GroupTypeEditModeBehavior::StartEditing(IDocument * pDoc, bool isCreating)
{
    const IEditMode* pGroupEditMode = IEditMode::Get(pDoc, GetEditModeType());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGroupEditMode != nullptr, L"pGroupEditMode为空",L"GDMPLab",L"2024-03-30");
    const IGroupType* pGroupType = quick_cast<const IGroupType>(pDoc->GetElement(pGroupEditMode->GetEditingElementId()));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGroupType != nullptr, L"pGroupType为空",L"GDMPLab",L"2024-03-30");

    FOR_EACH(eleId, pGroupType->GetElementIdsInGroupType())
    {
        IElement* pElement = pDoc->GetElement(eleId);
        DBG_WARN_AND_CONTINUE_UNLESS(pElement, L"pElement为空",L"GDMPLab",L"2024-03-30");
        IElementStatus* pStatus = pElement->GetStatus();
        DBG_WARN_AND_CONTINUE_UNLESS(pStatus, L"pStatus为空",L"GDMPLab",L"2024-03-30");

        pStatus->SetIsVisible(true);

        IGroup* pGroup = quick_cast<IGroup>(pElement);
        if (pGroup == nullptr)
        {
            continue;
        }
        UnorderedElementIdSet innerElements;
        pGroup->GetAllElementIdsInGroup(innerElements);
        for (auto& eleId : innerElements)
        {
            IElement* pElement = pDoc->GetElement(eleId);
            DBG_WARN_AND_CONTINUE_UNLESS(pElement, L"pElement为空",L"GDMPLab",L"2024-03-30");
            IElementStatus* pStatus = pElement->GetStatus();
            DBG_WARN_AND_CONTINUE_UNLESS(pStatus, L"pStatus为空",L"GDMPLab",L"2024-03-30");

            pStatus->SetIsVisible(true);
        }
    }
    // 如果组类型内有组，只修改组的可见性组内元素不会跟着刷新，会导致组内元素不可见
   /* if(pDoc->GetRegenerator())
        pDoc->GetRegenerator()->RegenerateDocument();*/

    StartToListenElementChanges(pDoc);
    return true;
}

bool GroupTypeEditModeBehavior::EndEditing(IDocument * pDoc)
{
    const IEditMode* pGroupEditMode = IEditMode::Get(pDoc, GetEditModeType());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGroupEditMode != nullptr, L"pGroupEditMode为空",L"GDMPLab",L"2024-03-30");
    const IGroupType* pGroupType = quick_cast<const IGroupType>(pDoc->GetElement(pGroupEditMode->GetEditingElementId()));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGroupType != nullptr, L"pGroupType为空",L"GDMPLab",L"2024-03-30");

    FOR_EACH(eleId, pGroupType->GetElementIdsInGroupType())
    {
        IElement* pElement = pDoc->GetElement(eleId);
        DBG_WARN_AND_CONTINUE_UNLESS(pElement, L"pElement为空",L"GDMPLab",L"2024-03-30");
        IElementStatus* pStatus = pElement->GetStatus();
        DBG_WARN_AND_CONTINUE_UNLESS(pStatus, L"pStatus为空",L"GDMPLab",L"2024-03-30");

        pStatus->SetIsVisible(false);

        IGroup* pGroup = quick_cast<IGroup>(pElement);
        if (pGroup == nullptr)
        {
            continue;
        }
        UnorderedElementIdSet innerElements;
        pGroup->GetAllElementIdsInGroup(innerElements);
        for (auto& eleId : innerElements)
        {
            IElement* pElement = pDoc->GetElement(eleId);
            DBG_WARN_AND_CONTINUE_UNLESS(pElement, L"pElement为空",L"GDMPLab",L"2024-03-30");
            IElementStatus* pStatus = pElement->GetStatus();
            DBG_WARN_AND_CONTINUE_UNLESS(pStatus, L"pStatus为空",L"GDMPLab",L"2024-03-30");

            pStatus->SetIsVisible(false);
        }
    }

    StopToListenElementChanges(pDoc);
    return true;
}

bool GroupTypeEditModeBehavior::IsElementEditable(const IElement * pElement) const
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pElement, L"传入指针pElement为空，不合法",L"GDMPLab",L"2024-03-30");
    IDocument * pDoc = pElement->GetDocument();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc != nullptr, L"pDoc为空",L"GDMPLab",L"2024-03-30");
    const IEditMode* pGroupEditMode = IEditMode::Get(pDoc, GetEditModeType());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGroupEditMode != nullptr,  L"pGroupEditMode为空",L"GDMPLab",L"2024-03-30");
    
    ElementId elemnetId = pElement->GetElementId();
    ElementId editingElementId = pGroupEditMode->GetEditingElementId();
    if (elemnetId == editingElementId)
        return true;

    const gcmp::IGroupType* pGroupType = quick_cast<const gcmp::IGroupType>(pDoc->GetElement(editingElementId));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGroupType != nullptr, L"pGroupType为空",L"GDMPLab",L"2024-03-30");
    const std::set<ElementId>& elementIdsInGroupType = pGroupType->GetElementIdsInGroupType();
    if (elementIdsInGroupType.find(elemnetId) != elementIdsInGroupType.end())
        return true;

    return false;
}

void GroupTypeEditModeBehavior::ReportParents(IDocument * pDoc, IElementParentReporter & reporter) const
{
    const IEditMode* pGroupTypeEditMode = IEditMode::Get(pDoc, GetEditModeType());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pGroupTypeEditMode != nullptr, L"pGroupTypeEditMode为空",L"GDMPLab",L"2024-03-30");
    if (pGroupTypeEditMode->GetEditingElementId() != ElementId::InvalidID)
    {
        reporter.ReportWeak(pGroupTypeEditMode->GetEditingElementId());
    }
}

void GroupTypeEditModeBehavior::UpdateForWeakParentDeletion(IDocument * pDoc, const std::set<ElementId>& deletedElementIds)
{
    IEditMode* pGroupTypeEditMode = IEditMode::Get(pDoc, GetEditModeType());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pGroupTypeEditMode != nullptr, L"pGroupTypeEditMode为空",L"GDMPLab",L"2024-03-30");
    if (pGroupTypeEditMode->GetEditingElementId() != ElementId::InvalidID && deletedElementIds.find(pGroupTypeEditMode->GetEditingElementId()) != deletedElementIds.end())
    {
        DBG_WARN(L"不应该在EditMode有效时删除其中引用的Element",L"GDMPLab",L"2024-03-30");
    }
}

void GroupTypeEditModeBehavior::StartToListenElementChanges(IDocument * pDoc)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(nullptr != pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");
    const IEditMode* pGroupEditMode = IEditMode::Get(pDoc, GetEditModeType());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pGroupEditMode != nullptr, L"pGroupEditMode为空",L"GDMPLab",L"2024-03-30");

    m_pElementChangeEventHandler = NEW_AS_OWNER_PTR(GroupTypeElementChangeHandler, pGroupEditMode->GetEditingElementId());
    pDoc->AddElementsChangeEventHandler(ElementsChangeEventType::ElementsPreDeletionEvent, m_pElementChangeEventHandler.get());
    pDoc->AddElementsChangeEventHandler(ElementsChangeEventType::ElementsPostUpdationEvent, m_pElementChangeEventHandler.get());
}

void GroupTypeEditModeBehavior::StopToListenElementChanges(IDocument * pDoc)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc != nullptr, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    pDoc->DeleteElementsChangeEventHandler(ElementsChangeEventType::ElementsPreDeletionEvent, m_pElementChangeEventHandler.get());
    pDoc->DeleteElementsChangeEventHandler(ElementsChangeEventType::ElementsPostUpdationEvent, m_pElementChangeEventHandler.get());
    m_pElementChangeEventHandler = nullptr;
}
